package com.googlecode.quillen.repository.aws;

import com.googlecode.quillen.domain.ObjectStorageException;
import com.googlecode.quillen.repository.ObjectStorage;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.jets3t.service.model.S3Object;
import org.jets3t.service.model.S3Bucket;
import org.jets3t.service.S3Service;
import org.jets3t.service.S3ServiceException;
import org.apache.commons.lang.StringUtils;

/**
 * Created by IntelliJ IDEA.
 * User: greg
 * Date: Dec 5, 2008
 * Time: 5:33:46 PM
 */
public class S3ObjectStorageImpl implements ObjectStorage
{
    private final S3Service s3service;

    public S3ObjectStorageImpl(S3Service s3service)
    {
        this.s3service = s3service;
    }

    public void createBucket(String bucket) throws ObjectStorageException
    {
        try
        {
            s3service.createBucket(getS3Bucket(bucket));
        }
        catch (S3ServiceException e)
        {
            throw wrapException(e);
        }
    }

    public void deleteBucket(String bucket) throws ObjectStorageException
    {
        try
        {
            for (String key : list(bucket))
            {
                delete(bucket, key);
            }
            
            s3service.deleteBucket(getS3Bucket(bucket));
        }
        catch (S3ServiceException e)
        {
            throw wrapException(e);
        }
    }

    public void put(String bucket, String key, byte[] data) throws ObjectStorageException
    {
        try
        {
            S3Object obj = new S3Object(key);

            InputStream in = new ByteArrayInputStream(data);
            try
            {
                obj.setDataInputStream(in);
                obj.setContentLength(data.length);
                s3service.putObject(getS3Bucket(bucket), obj);
            }
            finally
            {
                in.close();
            }
        }
        catch (S3ServiceException e)
        {
            throw wrapException(e);
        }
        catch (IOException e)
        {
            throw wrapException(e);
        }
    }

    public byte[] get(String bucket, String key) throws ObjectStorageException
    {
        try
        {
            S3Object obj = s3service.getObject(getS3Bucket(bucket), key);

            int bytesRead = 0;
            int totalBytes = (int) obj.getContentLength();
            byte[] data = new byte[totalBytes];

            InputStream in = obj.getDataInputStream();
            try
            {
                while (bytesRead < totalBytes)
                {
                    bytesRead += in.read(data, bytesRead, totalBytes - bytesRead);
                }

                return data;
            }
            finally
            {
                in.close();
            }
        }
        catch (S3ServiceException e)
        {
            throw wrapException(e);
        }
        catch (IOException e)
        {
            throw wrapException(e);
        }
    }

    public void delete(String bucket, String key) throws ObjectStorageException
    {
        try
        {
            s3service.deleteObject(getS3Bucket(bucket), key);
        }
        catch (S3ServiceException e)
        {
            throw wrapException(e);
        }
    }

    public String[] list(String bucket) throws ObjectStorageException
    {
        return list(bucket, null);
    }

    public String[] list(String bucket, String prefix) throws ObjectStorageException
    {
        try
        {
            // TODO: use listObjectsChunked?

            prefix = StringUtils.defaultString(prefix);
            S3Object[] objects = s3service.listObjects(getS3Bucket(bucket), prefix, null);
            String[] result = new String[objects.length];

            for (int i = 0; i < objects.length; i++)
            {
                result[i] = objects[i].getKey();
            }

            return result;
        }
        catch (S3ServiceException e)
        {
            throw wrapException(e);
        }
    }

    public S3Bucket getS3Bucket(String bucket)
    {
        return new S3Bucket(StringUtils.lowerCase("quillen-" + s3service.getAWSCredentials().getAccessKey() + "-" + bucket));
    }

    @SuppressWarnings("ThrowableInstanceNeverThrown")
    private ObjectStorageException wrapException(Exception e)
    {
        if (e instanceof ObjectStorageException)
        {
            return (ObjectStorageException) e;
        }
        else
        {
            return new ObjectStorageException(e);
        }
    }
}
